package com.bsdsma.visonManagementSystemapp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.bsdsma.visonManagementSystemapp.constants.ErrorCodes;
import com.bsdsma.visonManagementSystemapp.dto.*;
import com.bsdsma.visonManagementSystemapp.entity.Student;
import com.bsdsma.visonManagementSystemapp.entity.Teacher;
import com.bsdsma.visonManagementSystemapp.entity.Admin;
import com.bsdsma.visonManagementSystemapp.entity.School;
import com.bsdsma.visonManagementSystemapp.entity.User;
import com.bsdsma.visonManagementSystemapp.exceptionhandler.GlobalRuntimeException;
import com.bsdsma.visonManagementSystemapp.mapper.StudentMapper;
import com.bsdsma.visonManagementSystemapp.mapper.TeacherMapper;
import com.bsdsma.visonManagementSystemapp.mapper.AdminMapper;
import com.bsdsma.visonManagementSystemapp.service.UserService;
import com.bsdsma.visonManagementSystemapp.service.SchoolService;
import com.bsdsma.visonManagementSystemapp.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.Comparator;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    /**
     * 使用Spring注入Mybatis操作对象
     */
    @Autowired
    private StudentMapper studentMapper;
    @Autowired
    private TeacherMapper teacherMapper;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private SchoolService schoolService;
    @Value("${data-init.user.account}")
    private String initUserAccount;
    @Value("${data-init.user.password}")
    private String initUserPassword;
    @Value("${data-init.user.name}")
    private String initUserName;
    @Value("${data-init.user.xuehao}")
    private Long initUserXuehao;

    @Override
    public PageRetDto<UserDto> search(UserSearchDto dto) {
        log.info("Search DTO received: {}", dto);
        // Get current user from LocalUtils
        User currentUser = LocalUtils.getUser();
        if (currentUser == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请先登录");
        }

        // Convert current user to UserDto
        UserDto currentUserDto;
        if (currentUser instanceof Student) {
            currentUserDto = UserDto.fromStudent((Student) currentUser);
        } else if (currentUser instanceof Teacher) {
                currentUserDto = UserDto.fromTeacher((Teacher) currentUser);
        } else if (currentUser instanceof Admin) {
            currentUserDto = UserDto.fromAdmin((Admin) currentUser);
        } else {
            throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "无效的用户类型");
        }

        List<UserDto> allUsers = new ArrayList<>();
        long total = 0;

        // Role-based access control
        switch (currentUserDto.getRole()) {
            case "学生":
                // Students can only view their own information
                allUsers.add(currentUserDto);
                total = 1;
                break;

            case "教师":
                // Teachers can only view students from their school
                if (dto.getRole() != null && !"学生".equals(dto.getRole())) {
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "教师只能查看学生信息");
                }
                Long schoolId = schoolService.findByName(currentUserDto.getXuexiao()).getId();
                log.info("Teacher's school ID: {}", schoolId);
                QueryWrapper<Student> studentWrapper = new QueryWrapper<>();
                studentWrapper.eq("s.status", 0);
                studentWrapper.eq("s.xuexiao_id", schoolId);
                log.info("Initial SQL after setting entity: {}", studentWrapper.getSqlSegment());
                log.info("Initial params after setting entity: {}", studentWrapper.getParamNameValuePairs());
                // Don't apply school filter in addSearchCriteria since we already set it
                dto.setXuexiao(null);
                // Add other search criteria manually to avoid duplicate status condition
                if (!StringUtils.isBlank(dto.getAccount())) {
                    studentWrapper.like("s.account", "%" + dto.getAccount() + "%");
                }
                if (!StringUtils.isBlank(dto.getName())) {
                    studentWrapper.like("s.name", "%" + dto.getName() + "%");
                }
                if (!StringUtils.isBlank(dto.getCellphoneNumber())) {
                    studentWrapper.eq("s.cellphone_number", dto.getCellphoneNumber());
                }
                if (dto.getXuehao() != null) {
                    studentWrapper.eq("s.xuehao", dto.getXuehao());
                }
                if (!StringUtils.isBlank(dto.getNianji())) {
                    studentWrapper.eq("s.nianji", Student.Grade.fromDisplayName(dto.getNianji()));
                }
                if (dto.getBanji() != null) {
                    studentWrapper.eq("s.banji", dto.getBanji());
                }
                log.info("Final SQL for teacher search: {}", studentWrapper.getSqlSegment());
                log.info("Final params for teacher search: {}", studentWrapper.getParamNameValuePairs());
                PageDTO<Student> studentPage = new PageDTO<>(dto.getPage(), dto.getSize());
                IPage<Student> studentIPage = studentMapper.selectPageWithSchool(studentPage, studentWrapper);
                log.info("Found {} students", studentIPage.getRecords().size());
                allUsers.addAll(studentIPage.getRecords().stream()
                    .map(UserDto::fromStudent)
                    .collect(Collectors.toList()));
                total = studentIPage.getTotal();
                break;

            case "超级管理员":
                // Admin can view all users - need to handle pagination across multiple user types
                List<UserDto> allAdminUsers = new ArrayList<>();
                
                // Get all matching users without pagination first
                if (dto.getRole() == null || "学生".equals(dto.getRole()) || !StringUtils.isBlank(dto.getNianji()) || dto.getBanji() != null) {
                    Student studentSearch = new Student();
                    studentSearch.setStatus(0); // Only show active students
                    QueryWrapper<Student> studentSearchWrapper = new QueryWrapper<>(studentSearch);
                    addSearchCriteria(studentSearchWrapper, dto);
                    // Get all matching students without pagination
                    PageDTO<Student> studentSearchPage = new PageDTO<>(1, Integer.MAX_VALUE);
                    IPage<Student> studentSearchIPage = studentMapper.selectPageWithSchool(studentSearchPage, studentSearchWrapper);
                    allAdminUsers.addAll(studentSearchIPage.getRecords().stream()
                        .map(UserDto::fromStudent)
                        .collect(Collectors.toList()));
                }

                // Only include teachers if no grade or class is specified
                if ((dto.getRole() == null || "教师".equals(dto.getRole())) && StringUtils.isBlank(dto.getNianji()) && dto.getBanji() == null) {
                    Teacher teacherBean = new Teacher();
                    teacherBean.setStatus(0); // Only show active teachers
                    QueryWrapper<Teacher> teacherWrapper = new QueryWrapper<>(teacherBean);
                    addSearchCriteria(teacherWrapper, dto);
                    // Get all matching teachers without pagination
                    PageDTO<Teacher> teacherPage = new PageDTO<>(1, Integer.MAX_VALUE);
                    IPage<Teacher> teacherIPage = teacherMapper.selectPageWithSchool(teacherPage, teacherWrapper);
                    allAdminUsers.addAll(teacherIPage.getRecords().stream()
                        .map(UserDto::fromTeacher)
                        .collect(Collectors.toList()));
                }

                // Only include admin users if no school, grade, or class is specified
                if ((dto.getRole() == null || "超级管理员".equals(dto.getRole())) && 
                    StringUtils.isBlank(dto.getXuexiao()) && 
                    StringUtils.isBlank(dto.getNianji()) && 
                    dto.getBanji() == null) {
                    Admin adminBean = new Admin();
                    adminBean.setStatus(0); // Only show active admins
                    QueryWrapper<Admin> adminWrapper = new QueryWrapper<>(adminBean);
                    // Don't apply school filter for admins
                    if (!StringUtils.isBlank(dto.getAccount())) {
                        adminWrapper.like("account", "%" + dto.getAccount() + "%");
                    }
                    if (!StringUtils.isBlank(dto.getName())) {
                        adminWrapper.like("name", "%" + dto.getName() + "%");
                    }
                    if (!StringUtils.isBlank(dto.getCellphoneNumber())) {
                        adminWrapper.eq("cellphone_number", dto.getCellphoneNumber());
                    }
                    if (dto.getXuehao() != null) {
                        adminWrapper.eq("gonghao", dto.getXuehao());
                    }
                    // Get all matching admins without pagination
                    List<Admin> adminList = adminMapper.selectList(adminWrapper);
                    allAdminUsers.addAll(adminList.stream()
                        .map(UserDto::fromAdmin)
                        .collect(Collectors.toList()));
                }
                
                // Sort all users by creation time
                allAdminUsers.sort(Comparator.comparing(UserDto::getCt).reversed());
                
                // Apply pagination to the combined sorted results
                total = allAdminUsers.size();
                int start = (dto.getPage() - 1) * dto.getSize();
                int end = Math.min(start + dto.getSize(), allAdminUsers.size());
                allUsers = start < allAdminUsers.size() ? allAdminUsers.subList(start, end) : new ArrayList<>();
                break;

            default:
                throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "无效的用户角色");
        }

        // Sort and paginate the combined results
        if (!currentUserDto.getRole().equals("超级管理员")) {
            // For non-admin users, sorting is already handled
            allUsers.sort(Comparator.comparing(UserDto::getCt).reversed());
        }
        
        PageRetDto<UserDto> result = new PageRetDto<>();
        result.setTotalElements(total);
        result.setContent(allUsers);
        
        // Calculate hasNextPage properly
        if (currentUserDto.getRole().equals("超级管理员")) {
            // For admin, we handle pagination manually
            int currentPage = dto.getPage();
            int pageSize = dto.getSize();
            result.setHasNextPage(currentPage * pageSize < total);
        } else {
            // For other roles, pagination is handled at DB level
            result.setHasNextPage(false);
        }
        
        result.setPages((long) Math.ceil((double) total / dto.getSize()));
        return result;
    }

    private <T extends User> void addSearchCriteria(QueryWrapper<T> wrapper, UserSearchDto dto) {
        // Always filter out deleted users with proper table alias
        if (wrapper.getEntityClass() == Student.class) {
            wrapper.eq("s.status", 0);
        } else if (wrapper.getEntityClass() == Teacher.class) {
            wrapper.eq("t.status", 0);
        } else {
            wrapper.eq("status", 0);
        }
        
        if (!StringUtils.isBlank(dto.getAccount())) {
            if (wrapper.getEntityClass() == Student.class) {
                wrapper.like("s.account", "%" + dto.getAccount() + "%");
            } else if (wrapper.getEntityClass() == Teacher.class) {
                wrapper.like("t.account", "%" + dto.getAccount() + "%");
            } else {
                wrapper.like("account", "%" + dto.getAccount() + "%");
            }
        }
        if (!StringUtils.isBlank(dto.getName())) {
            if (wrapper.getEntityClass() == Student.class) {
                wrapper.like("s.name", "%" + dto.getName() + "%");
            } else if (wrapper.getEntityClass() == Teacher.class) {
                wrapper.like("t.name", "%" + dto.getName() + "%");
            } else {
                wrapper.like("name", "%" + dto.getName() + "%");
            }
        }
        if (!StringUtils.isBlank(dto.getCellphoneNumber())) {
            if (wrapper.getEntityClass() == Student.class) {
                wrapper.eq("s.cellphone_number", dto.getCellphoneNumber());
            } else if (wrapper.getEntityClass() == Teacher.class) {
                wrapper.eq("t.cellphone_number", dto.getCellphoneNumber());
            } else {
                wrapper.eq("cellphone_number", dto.getCellphoneNumber());
            }
        }

        // Handle xuehao search for all user types
        if (dto.getXuehao() != null) {
            if (wrapper.getEntityClass() == Student.class) {
                wrapper.eq("s.xuehao", dto.getXuehao());
            } else if (wrapper.getEntityClass() == Teacher.class) {
                wrapper.eq("t.gonghao", dto.getXuehao());
            } else if (wrapper.getEntityClass() == Admin.class) {
                wrapper.eq("gonghao", dto.getXuehao());
            }
        }

        // Only apply grade and class filters for students
        if (wrapper.getEntityClass() == Student.class) {
            if (!StringUtils.isBlank(dto.getNianji())) {
                wrapper.eq("s.nianji", Student.Grade.fromDisplayName(dto.getNianji()));
            }
            if (dto.getBanji() != null) {
                wrapper.eq("s.banji", dto.getBanji());
            }
        }

        // Apply school filter for both students and teachers
        if (wrapper.getEntityClass() == Student.class || wrapper.getEntityClass() == Teacher.class) {
            if (!StringUtils.isBlank(dto.getXuexiao())) {
                String tableAlias = wrapper.getEntityClass() == Student.class ? "s" : "t";
                // Use LIKE for partial school name matching
                wrapper.exists("SELECT 1 FROM school sc WHERE sc.id = " + tableAlias + ".xuexiao_id AND sc.name LIKE {0}", "%" + dto.getXuexiao() + "%");
            }
        }

        // If school is specified and this is an admin query, return no results
        if (!StringUtils.isBlank(dto.getXuexiao()) && wrapper.getEntityClass() == Admin.class) {
            wrapper.eq("1", "0"); // This will ensure no results are returned for admin queries when school is specified
        }
    }

    @Override
    public List<UserDto> listAll() {
        List<UserDto> allUsers = new ArrayList<>();

        // Get all active students with school relationship
        Student studentBean = new Student();
        studentBean.setStatus(0); // Only show active students
        QueryWrapper<Student> studentWrapper = new QueryWrapper<>(studentBean);
        PageDTO<Student> studentPage = new PageDTO<>(1, Integer.MAX_VALUE);
        IPage<Student> studentIPage = studentMapper.selectPageWithSchool(studentPage, studentWrapper);
        allUsers.addAll(studentIPage.getRecords().stream()
            .map(UserDto::fromStudent)
            .collect(Collectors.toList()));

        // Get all active teachers with school relationship
        Teacher teacherBean = new Teacher();
        teacherBean.setStatus(0); // Only show active teachers
        QueryWrapper<Teacher> teacherWrapper = new QueryWrapper<>(teacherBean);
        PageDTO<Teacher> teacherPage = new PageDTO<>(1, Integer.MAX_VALUE);
        IPage<Teacher> teacherIPage = teacherMapper.selectPageWithSchool(teacherPage, teacherWrapper);
        allUsers.addAll(teacherIPage.getRecords().stream()
            .map(UserDto::fromTeacher)
            .collect(Collectors.toList()));

        // Get all active admins
        Admin adminBean = new Admin();
        adminBean.setStatus(0); // Only show active admins
        List<Admin> admins = adminMapper.selectList(new QueryWrapper<>(adminBean));
        allUsers.addAll(admins.stream()
            .map(UserDto::fromAdmin)
            .collect(Collectors.toList()));

        return allUsers;
    }

    @Override
    public ListAllRetDto<UserDto> listAllWithRet() {
        List<UserDto> list = this.listAll();
        return new ListAllRetDto<>(false, list);
    }

    @Override
    public UserDto add(UserAddDto param, boolean isInit) {
        // 校验空字段
        if(StringUtils.isBlank(param.getAccount())){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入账号");
        }
        if(StringUtils.isBlank(param.getPassword())){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入密码");
        }
        if(StringUtils.isBlank(param.getName())){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入姓名");
        }
        if(StringUtils.isBlank(param.getRole())){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请选择角色");
        }
        // 校验账号是否已存在 (across all user types)
        validateAccountUniqueness(param.getAccount(), null);
        // 校验手机号是否已存在
        if(param.getCellphoneNumber() != null && !param.getCellphoneNumber().trim().isEmpty()){
            UserDto existUserByCellphoneNumber = this.getByCellphoneNumber(param.getCellphoneNumber());
            if(null != existUserByCellphoneNumber){
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "该手机号已存在");
            }
        }
        // 校验角色
        if(!param.getRole().equals("学生") && !param.getRole().equals("教师") && !param.getRole().equals("超级管理员")){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "角色不正确");
        }
        // 校验角色对应的字段
        if(param.getRole().equals("学生")){
            if(StringUtils.isBlank(param.getXuexiao())){
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入学校");
            }
            if(StringUtils.isBlank(param.getNianji())){
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入年级");
            }
            if(param.getBanji() == null){
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入班级");
            }
            if(param.getXuehao() == null){
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入学号");
            }
        }
        // 校验当前用户是否有权限添加用户
        if (!isInit) {
        User currentUser = LocalUtils.getUser();
        if (currentUser == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请先登录");
        }
        }
        // 校验当前用户是否有权限添加用户
        if(param.getRole().equals("超级管理员")){
            if (!isInit && !LocalUtils.getUser().getRole().equals("超级管理员")) {
                throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "只有超级管理员才能添加超级管理员");
            }
        }
        // 校验当前用户是否有权限添加用户
        if(param.getRole().equals("教师")){
            if (!isInit && !LocalUtils.getUser().getRole().equals("超级管理员")) {
                throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "只有超级管理员才能添加教师");
            }
        }
        // 校验当前用户是否有权限添加用户
        if(param.getRole().equals("学生")){
            if (!isInit && !LocalUtils.getUser().getRole().equals("超级管理员") && !LocalUtils.getUser().getRole().equals("教师")) {
                throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "只有超级管理员和教师才能添加学生");
            }
        }

        // Validate common fields
        validateCommonFields(param);

        switch (param.getRole()) {
            case "学生":
                return UserDto.fromStudent(addStudent(param));
            case "教师":
                return UserDto.fromTeacher(addTeacher(param));
            case "超级管理员":
                return UserDto.fromAdmin(addAdmin(param));
            default:
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "无效的角色类型");
        }
    }

    private void validateCommonFields(UserAddDto dto) {
        if (StringUtils.isBlank(dto.getAccount())) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写账号");
        }
        if (StringUtils.isBlank(dto.getPassword())) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写密码");
        }
        if (StringUtils.isBlank(dto.getName())) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写姓名");
        }
    }

    private void validateAccountUniqueness(String account, Long excludeId) {
        if (StringUtils.isBlank(account)) {
            return;
        }

        // Check student table
        Student student = new Student();
        student.setAccount(account);
        student.setStatus(0);
        QueryWrapper<Student> studentWrapper = new QueryWrapper<>(student);
        if (excludeId != null) {
            studentWrapper.ne("id", excludeId);
        }
        if (studentMapper.selectCount(studentWrapper) > 0) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "该账号已存在");
        }

        // Check teacher table
        Teacher teacher = new Teacher();
        teacher.setAccount(account);
        teacher.setStatus(0);
        QueryWrapper<Teacher> teacherWrapper = new QueryWrapper<>(teacher);
        if (excludeId != null) {
            teacherWrapper.ne("id", excludeId);
        }
        if (teacherMapper.selectCount(teacherWrapper) > 0) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "该账号已存在");
        }

        // Check admin table
        Admin admin = new Admin();
        admin.setAccount(account);
        admin.setStatus(0);
        QueryWrapper<Admin> adminWrapper = new QueryWrapper<>(admin);
        if (excludeId != null) {
            adminWrapper.ne("id", excludeId);
        }
        if (adminMapper.selectCount(adminWrapper) > 0) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "该账号已存在");
        }
    }

    private Student addStudent(UserAddDto dto) {
        if (StringUtils.isBlank(dto.getXuexiao())) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写学校");
        }

        // Check if school exists
        School school = schoolService.findByName(dto.getXuexiao());
        if (school == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "学校不存在");
        }

        try {
            Student.Grade grade = Student.Grade.fromDisplayName(dto.getNianji());
            if (grade == null) {
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入有效的年级（一年级到六年级）");
            }
        } catch (IllegalArgumentException e) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入有效的年级（一年级到六年级）");
        }
        if (dto.getBanji() == null || dto.getBanji() <= 0) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入有效的班级号（大于0的整数）");
        }
        if (dto.getXuehao() == null || dto.getXuehao() <= 0) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写学号");
        }

        Student student = new Student();
        populateCommonFields(student, dto);
        student.setXuexiaoId(school.getId());
        student.setNianji(Student.Grade.fromDisplayName(dto.getNianji()));
        student.setBanji(dto.getBanji());
        student.setXuehao(dto.getXuehao());
        studentMapper.insert(student);
        
        // Load the school relationship before returning
        return studentMapper.selectByIdWithSchool(student.getId());
    }

    private Teacher addTeacher(UserAddDto dto) {
        if (StringUtils.isBlank(dto.getXuexiao())) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写学校");
        }

        // Check if school exists
        School school = schoolService.findByName(dto.getXuexiao());
        if (school == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "学校不存在");
        }

        if (dto.getXuehao() == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写工号");
        }

        Teacher teacher = new Teacher();
        populateCommonFields(teacher, dto);
        teacher.setXuexiaoId(school.getId());
        teacher.setGonghao(dto.getXuehao()); // Using xuehao field for gonghao
        teacherMapper.insert(teacher);
        
        // Load the school relationship before returning
        return teacherMapper.selectByIdWithSchool(teacher.getId());
    }

    private Admin addAdmin(UserAddDto dto) {
        if (dto.getXuehao() == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写工号");
        }

        Admin admin = new Admin();
        populateCommonFields(admin, dto);
        admin.setGonghao(dto.getXuehao()); // Using xuehao field for gonghao
        adminMapper.insert(admin);
        return admin;
    }

    private <T extends User> void populateCommonFields(T user, UserAddDto dto) {
        user.setAccount(dto.getAccount());
        user.setPassword(dto.getPassword());
        user.setName(dto.getName());
        user.setCellphoneNumber(dto.getCellphoneNumber());
        user.setStatus(0);
        user.setCt(DateUtils.getNow());
        user.setUt(DateUtils.getNow());
    }

    @Override
    public UserDto update(Long id, UserAddDto dto) {
        // Get current user from LocalUtils
        User currentUser = LocalUtils.getUser();
        if (currentUser == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请先登录");
        }

        // Convert current user to UserDto
        UserDto currentUserDto;
        if (currentUser instanceof Student) {
            currentUserDto = UserDto.fromStudent((Student) currentUser);
        } else if (currentUser instanceof Teacher) {
            currentUserDto = UserDto.fromTeacher((Teacher) currentUser);
        } else if (currentUser instanceof Admin) {
            currentUserDto = UserDto.fromAdmin((Admin) currentUser);
        } else {
            throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "无效的用户类型");
        }

        String role = dto.getRole();
        if (StringUtils.isBlank(role)) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请选择角色");
        }

        // Get the user to be updated
        UserDto targetUser = this.getById(role, id);
        if (targetUser == null) {
            throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "用户不存在");
        }

        // Role-based access control
        switch (currentUserDto.getRole()) {
            case "学生":
                if (!currentUserDto.getId().equals(id)) {
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "学生只能修改自己的信息");
                }
                if (!"学生".equals(role)) {
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "学生不能修改自己的角色");
                }
                break;

            case "教师":
                if (!"学生".equals(targetUser.getRole())) {
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "教师只能修改学生信息");
                }
                if (!currentUserDto.getXuexiao().equals(targetUser.getXuexiao())) {
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "教师只能修改本校学生信息");
                }
                if (!"学生".equals(role)) {
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "教师不能修改学生角色");
                }
                if (!currentUserDto.getXuexiao().equals(dto.getXuexiao())) {
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "教师不能修改学生的学校");
                }
                break;

            case "超级管理员":
                // Admin can update any user
                break;

            default:
                throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "无效的用户角色");
        }

        // Validate common fields
        validateCommonFields(dto);

        // Check if account exists (excluding current user)
        validateAccountUniqueness(dto.getAccount(), id);

        switch (role) {
            case "学生":
                return updateStudent(id, dto);
            case "教师":
                return updateTeacher(id, dto);
            case "超级管理员":
                return updateAdmin(id, dto);
            default:
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "无效的角色类型");
        }
    }

    private UserDto updateStudent(Long id, UserAddDto dto) {
        Student student = studentMapper.selectByIdWithSchool(id);
        if (student == null) {
            throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "学生不存在");
        }

        if (StringUtils.isBlank(dto.getXuexiao())) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写学校");
        }
        try {
            Student.Grade grade = Student.Grade.fromDisplayName(dto.getNianji());
            if (grade == null) {
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入有效的年级（一年级到六年级）");
            }
        } catch (IllegalArgumentException e) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入有效的年级（一年级到六年级）");
        }
        if (dto.getBanji() == null || dto.getBanji() <= 0) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入有效的班级号（大于0的整数）");
        }
        if (dto.getXuehao() == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写学号");
        }

        updateCommonFields(student, dto);
        School school = schoolService.findByName(dto.getXuexiao());
        if (school != null) {
            student.setXuexiaoId(school.getId());
        }
        student.setNianji(Student.Grade.fromDisplayName(dto.getNianji()));
        student.setBanji(dto.getBanji());
        student.setXuehao(dto.getXuehao());
        studentMapper.updateById(student);
        return UserDto.fromStudent(student);
    }

    private UserDto updateTeacher(Long id, UserAddDto dto) {
        Teacher teacher = teacherMapper.selectByIdWithSchool(id);
        if (teacher == null) {
            throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "教师不存在");
        }

        if (StringUtils.isBlank(dto.getXuexiao())) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写学校");
        }
        if (dto.getXuehao() == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写工号");
        }

        updateCommonFields(teacher, dto);
        School school = schoolService.findByName(dto.getXuexiao());
        if (school != null) {
            teacher.setXuexiaoId(school.getId());
        }
        teacher.setGonghao(dto.getXuehao());
        teacherMapper.updateById(teacher);
        return UserDto.fromTeacher(teacher);
    }

    private UserDto updateAdmin(Long id, UserAddDto dto) {
        Admin admin = adminMapper.selectById(id);
        if (admin == null) {
            throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "管理员不存在");
        }

        if (dto.getXuehao() == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请填写工号");
        }

        updateCommonFields(admin, dto);
        admin.setGonghao(dto.getXuehao()); // Using xuehao field for gonghao
        adminMapper.updateById(admin);
        return UserDto.fromAdmin(admin);
    }

    private <T extends User> void updateCommonFields(T user, UserAddDto dto) {
        user.setAccount(dto.getAccount());
        user.setPassword(dto.getPassword());
        user.setName(dto.getName());
        user.setCellphoneNumber(dto.getCellphoneNumber());
        user.setUt(DateUtils.getNow());

        if (user instanceof Student) {
            Student student = (Student) user;
            School school = schoolService.findByName(dto.getXuexiao());
            if (school != null) {
                student.setXuexiaoId(school.getId());
            }
            student.setNianji(Student.Grade.fromDisplayName(dto.getNianji()));
            student.setBanji(dto.getBanji());
            student.setXuehao(dto.getXuehao());
        } else if (user instanceof Teacher) {
            Teacher teacher = (Teacher) user;
            School school = schoolService.findByName(dto.getXuexiao());
            if (school != null) {
                teacher.setXuexiaoId(school.getId());
            }
            teacher.setGonghao(dto.getXuehao());
        } else if (user instanceof Admin) {
            Admin admin = (Admin) user;
            admin.setGonghao(dto.getXuehao());
        }
    }

    @Override
    public UserDto getById(String role, Long id) {
        switch (role) {
            case "学生":
                Student student = studentMapper.selectByIdWithSchool(id);
                return student != null ? UserDto.fromStudent(student) : null;
            case "教师":
                Teacher teacher = teacherMapper.selectByIdWithSchool(id);
                return teacher != null ? UserDto.fromTeacher(teacher) : null;
            case "超级管理员":
                Admin admin = adminMapper.selectById(id);
                return admin != null ? UserDto.fromAdmin(admin) : null;
            default:
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "无效的角色类型");
        }
    }

    @Override
    public void delete(String role, Long id) {
        // Get current user from LocalUtils
        User currentUser = LocalUtils.getUser();
        if (currentUser == null) {
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请先登录");
        }

        // Convert current user to UserDto
        UserDto currentUserDto;
        if (currentUser instanceof Student) {
            currentUserDto = UserDto.fromStudent((Student) currentUser);
        } else if (currentUser instanceof Teacher) {
            currentUserDto = UserDto.fromTeacher((Teacher) currentUser);
        } else if (currentUser instanceof Admin) {
            currentUserDto = UserDto.fromAdmin((Admin) currentUser);
        } else {
            throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "无效的用户类型");
        }

        // Get the user to be deleted based on role
        UserDto targetUser = this.getById(role, id);
        if (targetUser == null) {
            throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "用户不存在");
        }

        // Role-based access control
        switch (currentUserDto.getRole()) {
            case "学生":
                throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "学生没有删除用户的权限");

            case "教师":
                if (!"学生".equals(targetUser.getRole())) {
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "教师只能删除学生用户");
                }
                if (!currentUserDto.getXuexiao().equals(targetUser.getXuexiao())) {
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "教师只能删除本校学生");
                }
                break;

            case "超级管理员":
                // Admin can delete any user
                break;

            default:
                throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "无效的用户角色");
        }

        // Delete based on role
        switch (role) {
            case "学生":
                Student student = studentMapper.selectById(id);
                if (student == null) {
                    throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "学生不存在");
                }
                student.setStatus(-1);
                student.setUt(DateUtils.getNow());
                if (studentMapper.updateById(student) <= 0) {
                    throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "删除学生失败");
                }
                break;

            case "教师":
                Teacher teacher = teacherMapper.selectById(id);
                if (teacher == null) {
                    throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "教师不存在");
                }
                teacher.setStatus(-1);
                teacher.setUt(DateUtils.getNow());
                if (teacherMapper.updateById(teacher) <= 0) {
                    throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "删除教师失败");
                }
                break;

            case "超级管理员":
                Admin admin = adminMapper.selectById(id);
                if (admin == null) {
                    throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "管理员不存在");
                }
                admin.setStatus(-1);
                admin.setUt(DateUtils.getNow());
                if (adminMapper.updateById(admin) <= 0) {
                    throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "删除管理员失败");
                }
                break;

            default:
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "无效的角色类型");
        }
    }

    @Override
    public int updateById(Long id, UserDto dto) {
        // Try to update in each user type
        Student student = studentMapper.selectById(id);
        if (student != null) {
            updateUserFromDto(student, dto);
            return studentMapper.updateById(student);
        }

        Teacher teacher = teacherMapper.selectById(id);
        if (teacher != null) {
            updateUserFromDto(teacher, dto);
            return teacherMapper.updateById(teacher);
        }

        Admin admin = adminMapper.selectById(id);
        if (admin != null) {
            updateUserFromDto(admin, dto);
            return adminMapper.updateById(admin);
        }

        throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "用户不存在");
    }

    private <T extends User> void updateUserFromDto(T user, UserDto dto) {
        user.setAccount(dto.getAccount());
        user.setPassword(dto.getPassword());
        user.setName(dto.getName());
        user.setCellphoneNumber(dto.getCellphoneNumber());
        user.setUt(DateUtils.getNow());

        if (user instanceof Student) {
            Student student = (Student) user;
            School school = schoolService.findByName(dto.getXuexiao());
            if (school != null) {
                student.setXuexiaoId(school.getId());
            }
            student.setNianji(Student.Grade.fromDisplayName(dto.getNianji()));
            student.setBanji(dto.getBanji());
            student.setXuehao(dto.getXuehao());
        } else if (user instanceof Teacher) {
            Teacher teacher = (Teacher) user;
            School school = schoolService.findByName(dto.getXuexiao());
            if (school != null) {
                teacher.setXuexiaoId(school.getId());
            }
            teacher.setGonghao(dto.getXuehao());
        } else if (user instanceof Admin) {
            Admin admin = (Admin) user;
            admin.setGonghao(dto.getXuehao());
        }
    }

    @Override
    public Long count() {
        long total = 0;

        Student studentBean = new Student();
        studentBean.setStatus(0);
        total += studentMapper.selectCount(new QueryWrapper<>(studentBean));

        Teacher teacherBean = new Teacher();
        teacherBean.setStatus(0);
        total += teacherMapper.selectCount(new QueryWrapper<>(teacherBean));

        Admin adminBean = new Admin();
        adminBean.setStatus(0);
        total += adminMapper.selectCount(new QueryWrapper<>(adminBean));

        return total;
    }

    @Override
    public List<DataGroupByDateDto> countByDay(Date beginDate, Date endDate) {
        List<DataGroupByDateDto> allCounts = new ArrayList<>();

        // Get counts from each user type
        List<DataGroupByDateDto> studentCounts = studentMapper.countByDay(beginDate, endDate);
        List<DataGroupByDateDto> teacherCounts = teacherMapper.countByDay(beginDate, endDate);
        List<DataGroupByDateDto> adminCounts = adminMapper.countByDay(beginDate, endDate);

        // Combine counts by date
        Map<String, DataGroupByDateDto> combinedCounts = new HashMap<>();
        
        for (DataGroupByDateDto dto : studentCounts) {
            combinedCounts.put(dto.getDay().toString(), dto);
        }

        for (DataGroupByDateDto dto : teacherCounts) {
            DataGroupByDateDto existing = combinedCounts.get(dto.getDay().toString());
            if (existing != null) {
                existing.setNum(existing.getNum() + dto.getNum());
            } else {
                combinedCounts.put(dto.getDay().toString(), dto);
            }
        }

        for (DataGroupByDateDto dto : adminCounts) {
            DataGroupByDateDto existing = combinedCounts.get(dto.getDay().toString());
            if (existing != null) {
                existing.setNum(existing.getNum() + dto.getNum());
            } else {
                combinedCounts.put(dto.getDay().toString(), dto);
            }
        }

        allCounts.addAll(combinedCounts.values());
        allCounts.sort(Comparator.comparing(DataGroupByDateDto::getDay));
        return allCounts;
    }

    @Override
    public UserDto getByAccount(String account) {
        if (StringUtils.isBlank(account)) {
            return null;
        }

        // Try to find in each user type
        Student student = new Student();
        student.setAccount(account);
        student.setStatus(0);
        Student foundStudent = studentMapper.selectOne(new QueryWrapper<>(student));
        if (foundStudent != null) {
            // Load the school relationship
            foundStudent = studentMapper.selectByIdWithSchool(foundStudent.getId());
            return UserDto.fromStudent(foundStudent);
        }

        Teacher teacher = new Teacher();
        teacher.setAccount(account);
        teacher.setStatus(0);
        Teacher foundTeacher = teacherMapper.selectOne(new QueryWrapper<>(teacher));
        if (foundTeacher != null) {
            // Load the school relationship
            foundTeacher = teacherMapper.selectByIdWithSchool(foundTeacher.getId());
            return UserDto.fromTeacher(foundTeacher);
        }

        Admin admin = new Admin();
        admin.setAccount(account);
        admin.setStatus(0);
        Admin foundAdmin = adminMapper.selectOne(new QueryWrapper<>(admin));
        if (foundAdmin != null) {
            return UserDto.fromAdmin(foundAdmin);
        }

        return null;
    }

    @Override
    public UserDto getByCellphoneNumber(String cellphoneNumber) {
        // Try to find in each user type
        Student student = new Student();
        student.setCellphoneNumber(cellphoneNumber);
        student.setStatus(0);
        Student foundStudent = studentMapper.selectOne(new QueryWrapper<>(student));
        if (foundStudent != null) {
            // Load the school relationship
            foundStudent = studentMapper.selectByIdWithSchool(foundStudent.getId());
            return UserDto.fromStudent(foundStudent);
        }

        Teacher teacher = new Teacher();
        teacher.setCellphoneNumber(cellphoneNumber);
        teacher.setStatus(0);
        Teacher foundTeacher = teacherMapper.selectOne(new QueryWrapper<>(teacher));
        if (foundTeacher != null) {
            // Load the school relationship
            foundTeacher = teacherMapper.selectByIdWithSchool(foundTeacher.getId());
            return UserDto.fromTeacher(foundTeacher);
        }

        Admin admin = new Admin();
        admin.setCellphoneNumber(cellphoneNumber);
        admin.setStatus(0);
        Admin foundAdmin = adminMapper.selectOne(new QueryWrapper<>(admin));
        if (foundAdmin != null) {
            return UserDto.fromAdmin(foundAdmin);
        }

        return null;
    }

    @Override
    public Map<String, Object> bulkImport(List<UserAddDto> userList) {
        Map<String, Object> result = new HashMap<>();
        List<String> successList = new ArrayList<>();
        List<String> failList = new ArrayList<>();

        for (UserAddDto dto : userList) {
            try {
                this.add(dto, false);
                successList.add(dto.getAccount());
            } catch (Exception e) {
                failList.add(dto.getAccount() + ":" + e.getMessage());
            }
        }

        result.put("success", successList);
        result.put("fail", failList);
        return result;
    }

    @PostConstruct
    public void initUser(){
        if(StringUtils.isBlank(this.initUserAccount)
            || StringUtils.isBlank(this.initUserPassword)
            || StringUtils.isBlank(this.initUserName)){
            return;
        }
        log.info("正在初始化用户[{}]-[{}]-[{}]，如果你希望跳过此步骤，" +
        "请将\"application-dev.yml\"中的\"data-init\"配置去掉",
        this.initUserAccount, this.initUserPassword, this.initUserName);
        UserDto initUser = this.getByAccount(this.initUserAccount);
        if(initUser != null){
            log.info("账号[{}]已初始化到系统，不再进行初始化", this.initUserAccount);
            return;
        }
        UserAddDto dto = new UserAddDto();
        dto.setAccount(this.initUserAccount);
        dto.setPassword(this.initUserPassword);
        dto.setName(this.initUserName);
        dto.setXuehao(this.initUserXuehao);
        dto.setRole("超级管理员");
        this.add(dto, true);
    }

    @Override
    public User getByXuehaoAndStatus(User user) {
        if (user == null) {
            return null;
        }

        // Try to find in each user type
        Student student = new Student();
        if (user instanceof Student) {
            student.setXuehao(((Student) user).getXuehao());
        } else if (user instanceof Teacher) {
            student.setXuehao(((Teacher) user).getGonghao());
        } else if (user instanceof Admin) {
            student.setXuehao(((Admin) user).getGonghao());
        } else {
            return null;
        }
        student.setStatus(user.getStatus());
        Student foundStudent = studentMapper.selectOne(new QueryWrapper<>(student));
        if (foundStudent != null) {
            return foundStudent;
        }

        Teacher teacher = new Teacher();
        if (user instanceof Student) {
            teacher.setGonghao(((Student) user).getXuehao());
        } else if (user instanceof Teacher) {
            teacher.setGonghao(((Teacher) user).getGonghao());
        } else if (user instanceof Admin) {
            teacher.setGonghao(((Admin) user).getGonghao());
        }
        teacher.setStatus(user.getStatus());
        Teacher foundTeacher = teacherMapper.selectOne(new QueryWrapper<>(teacher));
        if (foundTeacher != null) {
            return foundTeacher;
        }

        Admin admin = new Admin();
        if (user instanceof Student) {
            admin.setGonghao(((Student) user).getXuehao());
        } else if (user instanceof Teacher) {
            admin.setGonghao(((Teacher) user).getGonghao());
        } else if (user instanceof Admin) {
            admin.setGonghao(((Admin) user).getGonghao());
        }
        admin.setStatus(user.getStatus());
        Admin foundAdmin = adminMapper.selectOne(new QueryWrapper<>(admin));
        if (foundAdmin != null) {
            return foundAdmin;
        }

        return null;
    }

    @Override
    public List<Student> listAllStudentsBySchool(Long schoolId) {
        if (schoolId == null) {
            return new ArrayList<>();
        }
        School school = schoolService.getById(schoolId);
        if (school == null) {
            return new ArrayList<>();
        }

        Student student = new Student();
        student.setStatus(0);
        student.setXuexiaoId(school.getId());
        return studentMapper.selectList(new QueryWrapper<>(student));
    }

    @Override
    public Student getStudentByXuehaoAndStatus(Long xuehao, Integer status) {
        if (xuehao == null || status == null) {
            return null;
        }

        Student student = new Student();
        student.setXuehao(xuehao);
        student.setStatus(status);
        return studentMapper.selectOne(new QueryWrapper<>(student));
    }

    @Override
    public List<Student> searchStudents(Long schoolId, String grade, String name) {
        Student student = new Student();
        student.setStatus(0);
        QueryWrapper<Student> wrapper = new QueryWrapper<>(student);

        if (schoolId != null) {
            wrapper.eq("xuexiao_id", schoolId);
        }
        if (!StringUtils.isBlank(grade)) {
            wrapper.eq("nianji", grade);
        }
        if (!StringUtils.isBlank(name)) {
            wrapper.like("name", "%" + name + "%");
        }

        return studentMapper.selectList(wrapper);
    }
}
